using System;
using System.IO;
using System.Net;
using System.ComponentModel;

namespace ThatsMeSDK.Core
{
	/// <summary>
	/// Virtual Browser for Post and Get requests
	/// Works with MonoDroid and Monotouch
	/// </summary>
	internal class VBrowser
	{
		/// <summary>
		/// Browser Timout
		/// </summary>
		internal Int32 TimeOut { get; private set; }

		//Webrequest
		HttpWebRequest req;
		HttpWebResponse res;

		//CookieJar for Sessionhandling
		CookieContainer cookieJar;

		/// <summary>
		/// Creates a new VBrowser
		/// </summary>
		/// <param name="TimeOut">Connection Timeout</param>
		internal VBrowser(int TimeOut)
		{
			cookieJar = new CookieContainer();
			this.TimeOut = TimeOut;
		}

		/// <summary>
		/// Get Web Request
		/// </summary>
		/// <param name="uri">Content Uri</param>
		/// <returns>Returns the content of the requestet Uri</returns>
		internal string GetRequest(Uri uri)
		{  
#if SILVERLIGHT
            string html = "";
            this.downloadforWp7(uri, (r, ex) =>
                {
                    if (ex != null)
                    {
                        throw ex;
                    }
                    else
                    {
                        html =  r;
                    }
                });
            return html;
#else
            req = (HttpWebRequest)HttpWebRequest.Create(uri);
			
			req.CookieContainer = cookieJar;
			req.Method = "GET";
			req.KeepAlive = true;
			req.ServicePoint.Expect100Continue = false;
			req.Referer = uri.ToString();
			req.Timeout = TimeOut;
			req.UserAgent = ("User-Agent: TMAppSDK/1.0");
			req.ContentType = "application/x-www-form-urlencoded";
			res = (HttpWebResponse)req.GetResponse();

			return (new StreamReader(res.GetResponseStream()).ReadToEnd());
#endif
        }


		/// <summary>
		/// Post Web Request
		/// </summary>
		/// <param name="uri">Content Uri</param>
		/// <param name="PostDataBytes">Post data for the request</param>
		/// <returns>Returns the content of the requestet Uri</returns>
		internal string PostRequest(Uri uri, byte[] PostDataBytes)
		{
#if SILVERLIGHT
            throw new NotImplementedException();
#else
			req = (HttpWebRequest)HttpWebRequest.Create(uri);

			req.CookieContainer = cookieJar;
			req.Method = "POST";
			req.KeepAlive = false;
			req.Referer = uri.ToString();
			req.ServicePoint.Expect100Continue = false;
			req.Timeout = (TimeOut);
			req.UserAgent = ("User-Agent: TMAppSDK/1.0");
			req.ContentType = "application/x-www-form-urlencoded";

			req.ContentLength = PostDataBytes.Length;
			Stream stream = req.GetRequestStream();
			stream.Write(PostDataBytes, 0, PostDataBytes.Length);
			stream.Close();

			res = (HttpWebResponse)req.GetResponse();

			return (new StreamReader(res.GetResponseStream()).ReadToEnd());
#endif
        }

#if SILVERLIGHT
        public void downloadforWp7(Uri uri, Action<string, Exception> callback)
        {
            Exception ex = null;
            String r = null;
            WebClient wc = new WebClient();

            wc.DownloadStringCompleted += (sender, e) =>
            {
                r = e.Result;
                ex = e.Error;
                callback(r, ex);
            };

            wc.DownloadStringAsync(uri);
        }

        public static string DownloadString(this WebClient webClient, Uri address)
        {
            return Sync.Execute
                <DownloadStringCompletedEventArgs, string>
                (webClient, "DownloadStringCompleted",
                 (o) => webClient.DownloadStringAsync(address, o),
                 (e) => e.Result);
        }

        public static TResult Execute<TEventArgs, TResult>(object obj,
    string eventName,
    Action<object> asyncMethodInvoker,
    Func<TEventArgs, TResult> resultSelector)
        where TEventArgs : AsyncCompletedEventArgs
        {
            // Convert event to blocking IEnumerable
            var blocker = Observable.FromEvent<TEventArgs>(obj, eventName)
                .SubscribeOnDispatcher()
                .ToEnumerable();

            // Use Guid to identify our call 
            var guid = Guid.NewGuid();

            // Call the Async method
            asyncMethodInvoker(guid);

            // Get our element off the blocking Enumerable
            var eventArgs = blocker
                .First(e => e.EventArgs.UserState.Equals(guid))
                .EventArgs;

            // Throw exception?
            if (eventArgs.Error != null)
            {
                throw eventArgs.Error;
            }

            // Return result from EventArgs
            return resultSelector(eventArgs);
        }
#endif
    }
}
